package com.lagou.tool;

import com.lagou.MethodCalledTimeInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class PDPrintHelper {
    private static final Logger LOG = LoggerFactory.getLogger(PDPrintHelper.class);

    /**
     * 方法每次被调用时间,以方法名分组
     * key是方法名，value是方法被调用的时间信息
     */
    private final Map<String, List<MethodCalledTimeInfo>> calledTimeInfoMap = new HashMap<>();

    /**
     * true表示已开始打印
     */
    private volatile boolean startedPrint;

    public void put(MethodCalledTimeInfo monitorMethodInfo) {
        // 当发起第一次调用后，开始每隔5s打印TP90和TP99
        triggerPrint();
        String methodName = monitorMethodInfo.getMethodName();
        if (!calledTimeInfoMap.containsKey(methodName)) {
            calledTimeInfoMap.put(methodName, new ArrayList<>());
        }
        calledTimeInfoMap.get(methodName).add(monitorMethodInfo);
    }

    /**
     * 当发起第一次调用后，开始每隔5s打印TP90和TP99
     */
    private void triggerPrint() {
        if (!startedPrint) {
            startedPrint = true;
            Executors.newSingleThreadScheduledExecutor()
                    .scheduleWithFixedDelay(this::printTP, 5, 5, TimeUnit.SECONDS);
        }
    }

    private void printTP() {
        if (calledTimeInfoMap.size() == 0) {
            return;
        }
        LocalDateTime now = LocalDateTime.now();
        long currentTime = System.currentTimeMillis();
        long oneMinuteAgoTime = currentTime - 60000;
        calledTimeInfoMap.forEach((methodName, calledTimeInfos) -> {
            List<MethodCalledTimeInfo> sortedList = calledTimeInfos.stream()
                    // 筛选出一分钟以内的调用
                    .filter(info -> info.endTimeBetween(oneMinuteAgoTime, currentTime))
                    // 按耗时升序排序
                    .sorted(Comparator.comparingLong(MethodCalledTimeInfo::getSpendTime))
                    .collect(Collectors.toList());
            long tp90 = sortedList.get((int) (sortedList.size() * 0.9)).getSpendTime();
            long tp99 = sortedList.get((int) (sortedList.size() * 0.99)).getSpendTime();
//            System.out.printf("【%s】-【%s】,TP90: %sms,TP99: %sms\n", now, methodName, tp90, tp99);
            LOG.info("++++++,{}-{},TP90:{},TP99: {}", now, methodName, tp90, tp99);
        });
    }

}
